using micromsg;
using MicroMsg.Common.Utils;
using MicroMsg.Manager;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MicroMsg.Network
{
	public class HostService
	{
		public class HostInfo
		{
			public string mHost;
			public int mPort;
			public int mRetryLeft;
			public HostInfo(string host, int port, int retry)
			{
				this.mHost = host;
				this.mPort = port;
				this.mRetryLeft = retry;
			}
		}
		public class ConnectHost
		{
			private const string TAG = "Network";
			private const int DNS_TYPE = 0;
			private const int BUILTIN_TYPE = 1;
			private const int BAK_TYPE = 2;
			private static readonly string[] tagConnectInfo = new string[]
			{
				"longconn",
				"shortconn"
			};
			private static readonly string[] tagHostInfo = new string[]
			{
				"dns",
				"builtinip",
				"backup"
			};
			private static readonly int[] longConntPortMap = new int[]
			{
				80,
				443,
				8080
			};
			private static readonly int[] shortConnPortMap = new int[]
			{
				80
			};
			private static readonly int[] longConnRetry = new int[]
			{
				2,
				1,
				1
			};
			private static readonly int[] shortConnRetry = new int[]
			{
				3,
				1,
				1
			};
			private List<HostService.HostInfo> mDnsList = new List<HostService.HostInfo>();
			public List<HostService.HostInfo> mBuiltInList = new List<HostService.HostInfo>();
			private List<HostService.HostInfo> mBakList = new List<HostService.HostInfo>();
			private HostService.HostInfo mCurrentHost;
			private int mCurrentType;
			private uint mConnectType;
			private int[] getRetryArray()
			{
				if (this.mConnectType == 0u)
				{
					return HostService.ConnectHost.longConnRetry;
				}
				return HostService.ConnectHost.shortConnRetry;
			}
			private int[] getPortMap()
			{
				if (this.mConnectType == 0u)
				{
					return HostService.ConnectHost.longConntPortMap;
				}
				return HostService.ConnectHost.shortConnPortMap;
			}
			public ConnectHost(string[] dnsList, string[] bakList, uint connType)
			{
				this.mConnectType = connType;
				for (int i = 0; i < dnsList.Length; i++)
				{
					string host = dnsList[i];
					this.addHost(host, this.mDnsList, this.getRetryArray()[0], 0);
				}
				for (int j = 0; j < bakList.Length; j++)
				{
					string host2 = bakList[j];
					this.addHost(host2, this.mBakList, this.getRetryArray()[2], 2);
				}
			}
			public void setDNSFailed()
			{
				this.resetAvailableStatus(this.mDnsList, 0);
			}
			public HostService.HostInfo getAvailableHost()
			{
				if (HostService.mDebugMode)
				{
					return HostService.mDebugHost[(int)((UIntPtr)this.mConnectType)];
				}
				if (this.mCurrentHost == null)
				{
					this.mCurrentHost = this.getFirstAvailableItem(this.mDnsList);
					this.mCurrentType = 0;
					if (this.mCurrentHost == null)
					{
						Log.smethod_4("Network", "dns hosts are not available all, try builtin host...");
						this.mCurrentHost = this.getFirstAvailableItem(this.mBuiltInList);
						this.mCurrentType = 1;
					}
					if (this.mCurrentHost == null)
					{
						Log.smethod_4("Network", "builtin hosts are not available all, try backup host...");
						this.mCurrentHost = this.getFirstAvailableItem(this.mBakList);
						this.mCurrentType = 2;
					}
					if (this.mCurrentHost == null)
					{
						Log.smethod_4("Network", "all hosts are not available , try dns again...");
						this.resetAvailableStatus(this.mDnsList, this.getRetryArray()[0]);
						this.resetAvailableStatus(this.mBuiltInList, this.getRetryArray()[1]);
						this.resetAvailableStatus(this.mBakList, this.getRetryArray()[2]);
						this.mCurrentHost = this.mDnsList.get_Item(0);
						this.mCurrentType = 0;
					}
				}
				Log.smethod_5("Network", string.Concat(new object[]
				{
					"get available host = ",
					this.mCurrentHost.mHost,
					", port = ",
					this.mCurrentHost.mPort
				}));
				return this.mCurrentHost;
			}
			private HostService.HostInfo getFirstAvailableItem(List<HostService.HostInfo> listHost)
			{
				HostService.HostInfo result;
				using (List<HostService.HostInfo>.Enumerator enumerator = listHost.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						HostService.HostInfo current = enumerator.get_Current();
						if (current.mRetryLeft > 0)
						{
							result = current;
							return result;
						}
					}
					goto IL_3A;
				}
				return result;
				IL_3A:
				return null;
			}
			private void resetAvailableStatus(List<HostService.HostInfo> listHost, int retry)
			{
				using (List<HostService.HostInfo>.Enumerator enumerator = listHost.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						HostService.HostInfo current = enumerator.get_Current();
						current.mRetryLeft = retry;
					}
				}
			}
			public void onCurrentHostFailed()
			{
				if (this.mCurrentHost != null && !HostService.mDebugMode)
				{
					this.mCurrentHost.mRetryLeft--;
					if (this.mCurrentHost.mRetryLeft <= 0)
					{
						Log.smethod_1("Network", string.Concat(new object[]
						{
							"set current host not available , host = ",
							this.mCurrentHost.mHost,
							", port= ",
							this.mCurrentHost.mPort,
							", type=",
							this.mCurrentType
						}));
						this.mCurrentHost.mRetryLeft = 0;
						this.mCurrentHost = null;
					}
				}
			}
			public void onCurrentHostSuccess()
			{
				if (this.mCurrentHost != null && !HostService.mDebugMode)
				{
					this.mCurrentHost.mRetryLeft = this.getRetryArray()[this.mCurrentType];
				}
			}
			public void cleanBuiltInHost()
			{
				this.mBuiltInList.Clear();
			}
			public void addBuiltInHost(string host)
			{
				this.addHost(host, this.mBuiltInList, this.getRetryArray()[1], 1);
			}
			private void addHost(string host, List<HostService.HostInfo> listHost, int retry, int type)
			{
				if (listHost.get_Count() >= 18)
				{
					Log.smethod_1("Network", "add host too much , ignored host = " + host);
					return;
				}
				IEnumerable<HostService.HostInfo> enumerable = Enumerable.Where<HostService.HostInfo>(listHost, (HostService.HostInfo item) => item.mHost == host);
				if (Enumerable.Count<HostService.HostInfo>(enumerable) != 0)
				{
					Log.smethod_1("Network", "host exist already , ignored host = " + host);
					return;
				}
				int[] portMap = this.getPortMap();
				for (int i = 0; i < portMap.Length; i++)
				{
					int port = portMap[i];
					HostService.HostInfo hostInfo = new HostService.HostInfo(host, port, retry);
					listHost.Add(hostInfo);
				}
			}
			public void printInfo()
			{
				if (this.mCurrentHost != null)
				{
					Log.smethod_4("Network", string.Concat(new object[]
					{
						"current host ",
						this.mCurrentHost.mHost,
						":",
						this.mCurrentHost.mPort,
						", ",
						HostService.ConnectHost.tagConnectInfo[(int)((UIntPtr)this.mConnectType)],
						", ",
						HostService.ConnectHost.tagHostInfo[this.mCurrentType]
					}));
				}
			}
			public string getCurrentHostString()
			{
				if (this.mCurrentHost != null)
				{
					return this.mCurrentHost.mHost + ":" + this.mCurrentHost.mPort;
				}
				return "";
			}
		}
		private const uint TYPE_LONG_CONN = 0u;
		private const uint TYPE_SHORT_CONN = 1u;
		public static readonly string[] constLongDnsList = new string[]
		{
			"long.weixin.qq.com"
		};
		public static readonly string[] constShortDnsList = new string[]
		{
			"short.weixin.qq.com"
		};
		public static readonly string[] constLongBakHostList = new string[]
		{
			"120.204.201.146",
			"112.64.200.218",
			"112.64.237.188",
			"180.153.82.30",
			"180.153.218.191",
			"117.135.130.187"
		};
		public static readonly string[] constShortBakHostList = new string[]
		{
			"112.64.200.240",
			"112.64.237.186",
			"180.153.82.27",
			"117.135.130.177",
			"180.153.218.192",
			"120.204.201.143"
		};
		public static HostService.ConnectHost mLongConnHosts = null;
		public static HostService.ConnectHost mShortConnHosts = null;
		public static bool mDebugMode = false;
		public static HostService.HostInfo[] mDebugHost = new HostService.HostInfo[]
		{
			new HostService.HostInfo("180.153.74.12", 8080, 0),
			new HostService.HostInfo("180.153.74.10", 80, 0)
		};
		public static void setDebugMode(bool enable)
		{
			HostService.mDebugMode = enable;
			Connector.close();
		}
		public static void setDebugHost(string longHost, string shortHost)
		{
			if (!string.IsNullOrEmpty(longHost))
			{
				HostService.mDebugHost[(int)((UIntPtr)0)].mHost = longHost;
			}
			if (!string.IsNullOrEmpty(shortHost))
			{
				HostService.mDebugHost[(int)((UIntPtr)1)].mHost = shortHost;
			}
		}
		public static void init()
		{
			if (HostService.mLongConnHosts == null)
			{
				HostService.mLongConnHosts = new HostService.ConnectHost(HostService.constLongDnsList, HostService.constLongBakHostList, 0u);
			}
			if (HostService.mShortConnHosts == null)
			{
				HostService.mShortConnHosts = new HostService.ConnectHost(HostService.constShortDnsList, HostService.constShortBakHostList, 1u);
			}
			HostService.loadLocalBuiltinIP();
		}
		public static void setDNSFailed()
		{
			if (HostService.mLongConnHosts != null)
			{
				HostService.mLongConnHosts.setDNSFailed();
			}
			if (HostService.mShortConnHosts != null)
			{
				HostService.mShortConnHosts.setDNSFailed();
			}
		}
		public static void printInfo()
		{
			if (HostService.mLongConnHosts != null)
			{
				HostService.mLongConnHosts.printInfo();
			}
			if (HostService.mShortConnHosts != null)
			{
				HostService.mShortConnHosts.printInfo();
			}
		}
		private static void loadLocalBuiltinIP()
		{
			ServerHost serverHost = GConfigMgr.read<ServerHost>();
			if (serverHost != null && serverHost.addrList != null)
			{
				using (List<ServerAddress>.Enumerator enumerator = serverHost.addrList.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						ServerAddress current = enumerator.get_Current();
						if (current.nType == 0u)
						{
							HostService.mLongConnHosts.addBuiltInHost(Util.ByteArrayToString(current.bytesIP));
						}
						else
						{
							if (current.nType == 1u)
							{
								HostService.mShortConnHosts.addBuiltInHost(Util.ByteArrayToString(current.bytesIP));
							}
						}
					}
				}
				return;
			}
		}
		public static byte[] trimBytesArray(byte[] buffer)
		{
			int num = 0;
			if (buffer == null)
			{
				return null;
			}
			for (int i = 0; i < buffer.Length; i++)
			{
				byte b = buffer[i];
				if (b == 0)
				{
					break;
				}
				num++;
			}
			if (num == 0)
			{
				return null;
			}
			byte[] array = new byte[num];
			Buffer.BlockCopy(buffer, 0, array, 0, num);
			return array;
		}
		public static void updateAuthBuiltinIP(BuiltinIPList ipList)
		{
			ServerHost serverHost = new ServerHost();
			if (ipList.LongConnectIPListCount > 0)
			{
				HostService.mLongConnHosts.cleanBuiltInHost();
				using (IEnumerator<BuiltinIP> enumerator = ipList.LongConnectIPListList.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						BuiltinIP current = enumerator.get_Current();
						byte[] array = HostService.trimBytesArray(current.IP.ToByteArray());
						if (array != null)
						{
							HostService.mLongConnHosts.addBuiltInHost(Util.ByteArrayToString(array));
							serverHost.addrList.Add(new ServerAddress
							{
								nType = 0u,
								bytesIP = array
							});
						}
					}
				}
			}
			if (ipList.ShortConnectIPListCount > 0)
			{
				HostService.mShortConnHosts.cleanBuiltInHost();
				using (IEnumerator<BuiltinIP> enumerator2 = ipList.ShortConnectIPListList.GetEnumerator())
				{
					while (enumerator2.MoveNext())
					{
						BuiltinIP current2 = enumerator2.get_Current();
						byte[] array2 = HostService.trimBytesArray(current2.IP.ToByteArray());
						if (array2 != null)
						{
							HostService.mShortConnHosts.addBuiltInHost(Util.ByteArrayToString(array2));
							serverHost.addrList.Add(new ServerAddress
							{
								nType = 1u,
								bytesIP = array2
							});
						}
					}
				}
			}
			if (ipList.LongConnectIPListCount > 0 || ipList.ShortConnectIPListCount > 0)
			{
				GConfigMgr.write<ServerHost>(serverHost);
			}
		}
	}
}
